package org.sofun.subscription.example;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.sofun.subscription.enums.DayType;
import org.sofun.subscription.enums.OffsetType;
import org.sofun.subscription.enums.OpenDayOrder;
import org.sofun.subscription.enums.TradeFrequency;
import org.sofun.subscription.model.FundPeriod;
import org.sofun.subscription.model.SubscriptionRule;
import org.sofun.subscription.service.SubscriptionService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.List;

/**
 * 申购服务使用示例
 */
@Component
public class SubscriptionServiceExample {

    private static final Logger logger = LoggerFactory.getLogger(SubscriptionServiceExample.class);

    @Autowired
    private SubscriptionService subscriptionService;
    
    /**
     * 示例1：月度申购，正数第1个自然日
     */
    public void example1() {
        logger.info("=== 示例1：月度申购，正数第1个自然日 ===");

        // 1. 构建申购规则参数
        SubscriptionRule rule = new SubscriptionRule();
        rule.setTradeFrequency(TradeFrequency.MONTHLY);
        rule.setOpenDayOrder(OpenDayOrder.POSITIVE);
        rule.setOpenDayIndex(1);
        rule.setOpenDayType(DayType.NATURAL_DAY);
        rule.setCloseDayOffset(3);
        rule.setOffsetType(OffsetType.NATURAL_DAY);
        rule.setCutoffTime(LocalTime.of(14, 0));
        rule.setInitialDateTime(LocalDateTime.of(2025, 5, 1, 14, 0));

        logger.info("申购规则配置: {}", rule);

        // 2. 生成申购开放日
        LocalDate startDate = LocalDate.of(2025, 6, 1);
        LocalDate endDate = LocalDate.of(2025, 8, 31);

        List<LocalDate> openDays = subscriptionService.generateOpenDaysWithExceptionHandling(rule, startDate, endDate, null);
        logger.info("开放日列表: {}", openDays);

        // 3. 计算募集期间
        List<FundPeriod> fundPeriods = subscriptionService.calculateFundPeriodsWithExceptionHandling(openDays, rule);

        // 4. 输出结果
        printFundPeriods(fundPeriods);
    }
    
    /**
     * 示例2：季度申购，倒数第2个工作日
     */
    public void example2() {
        logger.info("=== 示例2：季度申购，倒数第2个工作日 ===");

        // 1. 构建申购规则参数
        SubscriptionRule rule = new SubscriptionRule();
        rule.setTradeFrequency(TradeFrequency.QUARTERLY);
        rule.setOpenDayOrder(OpenDayOrder.NEGATIVE);
        rule.setOpenDayIndex(2);
        rule.setOpenDayType(DayType.WORKING_DAY);
        rule.setCloseDayOffset(5);
        rule.setOffsetType(OffsetType.WORKING_DAY);
        rule.setCutoffTime(LocalTime.of(15, 30));
        rule.setInitialDateTime(LocalDateTime.of(2025, 3, 1, 15, 30));

        logger.info("申购规则配置: {}", rule);

        // 2. 生成申购开放日（按期数）
        LocalDate startDate = LocalDate.of(2025, 4, 1);
        Integer periodCount = 3; // 生成3期

        List<LocalDate> openDays = subscriptionService.generateOpenDaysWithExceptionHandling(rule, startDate, null, periodCount);
        logger.info("开放日列表: {}", openDays);

        // 3. 计算募集期间
        List<FundPeriod> fundPeriods = subscriptionService.calculateFundPeriodsWithExceptionHandling(openDays, rule);

        // 4. 输出结果
        printFundPeriods(fundPeriods);
    }
    
    /**
     * 示例3：年度申购，正数第10个工作日
     */
    public void example3() {
        logger.info("=== 示例3：年度申购，正数第10个工作日 ===");

        // 1. 构建申购规则参数
        SubscriptionRule rule = new SubscriptionRule();
        rule.setTradeFrequency(TradeFrequency.ANNUAL);
        rule.setOpenDayOrder(OpenDayOrder.POSITIVE);
        rule.setOpenDayIndex(10);
        rule.setOpenDayType(DayType.WORKING_DAY);
        rule.setCloseDayOffset(7);
        rule.setOffsetType(OffsetType.NATURAL_DAY);
        rule.setCutoffTime(LocalTime.of(16, 0));
        rule.setInitialDateTime(LocalDateTime.of(2024, 12, 1, 16, 0));

        logger.info("申购规则配置: {}", rule);

        // 2. 生成申购开放日
        LocalDate startDate = LocalDate.of(2025, 1, 1);
        LocalDate endDate = LocalDate.of(2027, 12, 31);

        List<LocalDate> openDays = subscriptionService.generateOpenDaysWithExceptionHandling(rule, startDate, endDate, null);
        logger.info("开放日列表: {}", openDays);

        // 3. 计算募集期间
        List<FundPeriod> fundPeriods = subscriptionService.calculateFundPeriodsWithExceptionHandling(openDays, rule);

        // 4. 输出结果
        printFundPeriods(fundPeriods);
    }
    
    /**
     * 打印基金期间信息
     */
    private void printFundPeriods(List<FundPeriod> fundPeriods) {
        DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm");

        logger.info("基金期间详情:");
        logger.info("序号\t开放日\t\t募集期起始日\t\t募集期结束日\t\t订单归集规则");
        logger.info("----\t--------\t----------------\t----------------\t----------------");

        for (int i = 0; i < fundPeriods.size(); i++) {
            FundPeriod period = fundPeriods.get(i);
            logger.info("{}\t{}\t{}\t{}\t{}",
                i + 1,
                period.getOpenDay().format(dateFormatter),
                period.getStartDateTime().format(dateTimeFormatter),
                period.getCloseDateTime().format(dateTimeFormatter),
                period.getRuleDescription());
        }
    }
    
    /**
     * 示例4：演示跳过已过期开放日的功能
     */
    public void example4() {
        logger.info("=== 示例4：跳过已过期开放日功能演示 ===");

        // 1. 构建申购规则参数
        SubscriptionRule rule = new SubscriptionRule();
        rule.setTradeFrequency(TradeFrequency.MONTHLY);
        rule.setOpenDayOrder(OpenDayOrder.POSITIVE);
        rule.setOpenDayIndex(1);
        rule.setOpenDayType(DayType.NATURAL_DAY);
        rule.setCloseDayOffset(3);
        rule.setOffsetType(OffsetType.NATURAL_DAY);
        rule.setCutoffTime(LocalTime.of(14, 0));
        rule.setInitialDateTime(LocalDateTime.of(2024, 12, 1, 14, 0));

        logger.info("申购规则配置: {}", rule);

        // 2. 设置开始日期为过去的日期，演示系统会跳过已过期的开放日
        LocalDate startDate = LocalDate.of(2024, 6, 1); // 过去的日期
        LocalDate endDate = LocalDate.now().plusMonths(6); // 未来6个月

        logger.info("开始日期: {} (过去的日期)", startDate);
        logger.info("结束日期: {} (未来的日期)", endDate);
        logger.info("当前日期: {}", LocalDate.now());

        List<LocalDate> openDays = subscriptionService.generateOpenDaysWithExceptionHandling(rule, startDate, endDate, null);
        logger.info("生成的开放日列表: {}", openDays);

        // 3. 验证所有开放日都是未来日期
        LocalDate today = LocalDate.now();
        boolean allFutureDates = openDays.stream().allMatch(date -> date.isAfter(today));
        logger.info("所有开放日都是未来日期: {}", allFutureDates);

        if (!openDays.isEmpty()) {
            logger.info("最近的开放日: {}", openDays.get(0));
            logger.info("最远的开放日: {}", openDays.get(openDays.size() - 1));
        }

        // 4. 计算募集期间
        List<FundPeriod> fundPeriods = subscriptionService.calculateFundPeriodsWithExceptionHandling(openDays, rule);

        // 5. 输出结果
        printFundPeriods(fundPeriods);
    }

    /**
     * 运行所有示例
     */
    public void runAllExamples() {
        try {
            logger.info("开始运行所有示例");
            example1();
            example2();
            example3();
            example4(); // 添加新示例
            logger.info("所有示例运行完成");
        } catch (Exception e) {
            logger.error("运行示例时发生异常: {}", e.getMessage(), e);
        }
    }
}
